home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
nethack.lha
/
nethack-3.1
/
src
/
rumors.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-01-21
|
9KB
|
321 lines
/* SCCS Id: @(#)rumors.c 3.1 92/12/05 */
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed. See license for details. */
#include "hack.h"
/* [note: this comment is fairly old, but still accurate for 3.1]
* Rumors have been entirely rewritten to speed up the access. This is
* essential when working from floppies. Using fseek() the way that's done
* here means rumors following longer rumors are output more often than those
* following shorter rumors. Also, you may see the same rumor more than once
* in a particular game (although the odds are highly against it), but
* this also happens with real fortune cookies. -dgk
*/
/* 3.1
* The rumors file consists of a "do not edit" line, a hexadecimal number
* giving the number of bytes of useful/true rumors, followed by those
* true rumors (one per line), followed by the useless/false/misleading/cute
* rumors (also one per line). Number of bytes of untrue rumors is derived
* via fseek(EOF)+ftell().
*
* The oracles file consists of a "do not edit" comment, a decimal count N
* and set of N+1 hexadecimal fseek offsets, followed by N multiple-line
* records, separated by "---" lines. The first oracle is a special case,
* and placed there by 'makedefs'.
*/
#ifndef SEEK_SET
# define SEEK_SET 0
#endif
#ifndef SEEK_CUR
# define SEEK_CUR 1
#endif
#ifndef SEEK_END /* aka SEEK_EOF */
# define SEEK_END 2
#endif
static void FDECL(init_rumors, (FILE *));
static void FDECL(init_oracles, (FILE *));
static void FDECL(outoracle, (BOOLEAN_P));
static long true_rumor_start, true_rumor_size, true_rumor_end,
false_rumor_start, false_rumor_size, false_rumor_end;
static int oracle_flg = 0; /* -1=>don't use, 0=>need init, 1=>init done */
static unsigned oracle_cnt = 0;
static long *oracle_loc = 0;
static void
init_rumors(fp)
FILE *fp;
{
char line[BUFSZ];
(void) fgets(line, sizeof line, fp); /* skip "don't edit" comment */
if (fscanf(fp, "%6lx\n", &true_rumor_size) == 1 &&
true_rumor_size > 0L) {
(void) fseek(fp, 0L, SEEK_CUR);
true_rumor_start = ftell(fp);
true_rumor_end = true_rumor_start + true_rumor_size;
(void) fseek(fp, 0L, SEEK_END);
false_rumor_end = ftell(fp);
false_rumor_start = true_rumor_end; /* ok, so it's redundant... */
false_rumor_size = false_rumor_end - false_rumor_start;
} else
true_rumor_size = -1L; /* init failed */
}
char *
getrumor(truth)
int truth; /* 1=true, -1=false, 0=either */
{
static char rumor_buf[COLNO + 28];
FILE *rumors;
long tidbit, beginning;
char *endp, line[sizeof rumor_buf];
rumor_buf[0] = '\0';
if (true_rumor_size < 0L) /* we couldn't open RUMORFILE */
return rumor_buf;
rumors = fopen_datafile(RUMORFILE, "r");
if (rumors) {
if (true_rumor_size == 0L) { /* if this is 1st outrumor() */
init_rumors(rumors);
if (true_rumor_size < 0L) { /* init failed */
Sprintf(rumor_buf, "Error reading \"%.80s\".",
RUMORFILE);
return rumor_buf;
}
}
/*
* input: 1 0 -1
* rn2 \ +1 2=T 1=T 0=F
* adj./ +0 1=T 0=F -1=F
*/
switch (truth += rn2(2)) {
case 2: /*(might let a bogus input arg sneak thru)*/
case 1: beginning = true_rumor_start;
tidbit = Rand() % true_rumor_size;
break;
case 0: /* once here, 0 => false rather than "either"*/
case -1: beginning = false_rumor_start;
tidbit = Rand() % false_rumor_size;
break;
default:
impossible("strange truth value for rumor");
return strcpy(rumor_buf, "Oops...");
}
(void) fseek(rumors, beginning + tidbit, SEEK_SET);
(void) fgets(line, sizeof line, rumors);
if (!fgets(line, sizeof line, rumors) ||
(truth > 0 && ftell(rumors) > true_rumor_end)) {
/* reached end of rumors -- go back to beginning */
(void) fseek(rumors, beginning, SEEK_SET);
(void) fgets(line, sizeof line, rumors);
}
if ((endp = index(line, '\n')) != 0) *endp = 0;
Strcat(rumor_buf, xcrypt(line));
(void) fclose(rumors);
exercise(A_WIS, (truth > 0));
} else {
pline("Can't open rumors file!");
true_rumor_size = -1; /* don't try to open it again */
}
return rumor_buf;
}
void
outrumor(truth, cookie)
int truth; /* 1=true, -1=false, 0=either */
boolean cookie;
{
static const char fortune_msg[] =
"This cookie has a scrap of paper inside.";
const char *line;
if (cookie && Blind) {
pline(fortune_msg);
pline("What a pity that you cannot read it!");
return;
}
line = getrumor(truth);
if (!*line)
line = "NetHack rumors file closed for renovation.";
if (cookie) {
pline(fortune_msg);
pline("It reads:");
pline("%s", line);
} else { /* if the Oracle is the only alternative */
pline("True to her word, the Oracle %ssays: ",
(!rn2(4) ? "offhandedly " : (!rn2(3) ? "casually " :
(rn2(2) ? "nonchalantly " : ""))));
verbalize("%s", line);
exercise(A_WIS, TRUE);
}
}
static void
init_oracles(fp)
FILE *fp;
{
register int i;
char line[BUFSZ];
int cnt = 0;
/* this assumes we're only called once */
(void) fgets(line, sizeof line, fp); /* skip "don't edit" comment */
if (fscanf(fp, "%5d", &cnt) == 1 && cnt > 0) {
oracle_cnt = (unsigned) cnt;
oracle_loc = (long *) alloc(cnt * sizeof (long));
for (i = 0; i < cnt; i++)
(void) fscanf(fp, "%5lx", &oracle_loc[i]);
}
return;
}
void
save_oracles(fd)
int fd;
{
bwrite(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt);
if (oracle_cnt)
bwrite(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof (long));
}
void
restore_oracles(fd)
int fd;
{
mread(fd, (genericptr_t) &oracle_cnt, sizeof oracle_cnt);
if (oracle_cnt) {
oracle_loc = (long *) alloc(oracle_cnt * sizeof (long));
mread(fd, (genericptr_t) oracle_loc, oracle_cnt * sizeof (long));
oracle_flg = 1; /* no need to call init_oracles() */
}
}
static void
outoracle(special)
boolean special;
{
char line[COLNO];
char *endp;
FILE *oracles;
int oracle_idx;
if(oracle_flg < 0 || /* couldn't open ORACLEFILE */
(oracle_flg > 0 && oracle_cnt == 0)) /* oracles already exhausted */
return;
oracles = fopen_datafile(ORACLEFILE, "r");
if (oracles) {
winid tmpwin;
if (oracle_flg == 0) { /* if this is the first outoracle() */
init_oracles(oracles);
oracle_flg = 1;
if (oracle_cnt == 0) return;
}
/* oracle_loc[0] is the special oracle; */
/* oracle_loc[1..oracle_cnt-1] are normal ones */
if (oracle_cnt <= 1 && !special) return; /*(shouldn't happen)*/
oracle_idx = special ? 0 : rnd((int) oracle_cnt - 1);
(void) fseek(oracles, oracle_loc[oracle_idx], SEEK_SET);
if (!special) oracle_loc[oracle_idx] = oracle_loc[--oracle_cnt];
tmpwin = create_nhwindow(NHW_TEXT);
putstr(tmpwin, 0, special ?
"The Oracle scornfully takes all your money and says:" :
"The Oracle meditates for a moment and then intones:");
putstr(tmpwin, 0, "");
while (fgets(line, COLNO, oracles) && strcmp(line,"---\n")) {
if ((endp = index(line, '\n')) != 0) *endp = 0;
putstr(tmpwin, 0, xcrypt(line));
}
display_nhwindow(tmpwin, TRUE);
destroy_nhwindow(tmpwin);
(void) fclose(oracles);
} else {
pline("Can't open oracles file!");
oracle_flg = -1; /* don't try to open it again */
}
}
int
doconsult(oracl)
register struct monst *oracl;
{
int u_pay, minor_cost = 50, major_cost = 500 + 50 * u.ulevel;
int add_xpts;
char qbuf[QBUFSZ];
multi = 0;
if (!oracl) {
pline("There is no one here to consult.");
return 0;
} else if (!oracl->mpeaceful) {
pline("The Oracle is in no mood for consultations.");
return 0;
} else if (!u.ugold) {
You("have no money.");
return 0;
}
Sprintf(qbuf,
"\"Wilt thou settle for a minor consultation?\" (%d zorkmids)",
minor_cost);
switch (ynq(qbuf)) {
default:
case 'q':
return 0;
case 'y':
if (u.ugold < (long)minor_cost) {
You("don't even have enough money for that!");
return 0;
}
u_pay = minor_cost;
break;
case 'n':
if (u.ugold <= (long)minor_cost || /* don't even ask */
(oracle_cnt == 1 || oracle_flg < 0)) return 0;
Sprintf(qbuf,
"\"Then dost thou desire a major one?\" (%d zorkmids)",
major_cost);
if (yn(qbuf) != 'y') return 0;
u_pay = (u.ugold < (long)major_cost ? (int)u.ugold
: major_cost);
break;
}
u.ugold -= (long)u_pay;
oracl->mgold += (long)u_pay;
flags.botl = 1;
add_xpts = 0; /* first oracle of each type gives experience points */
if (u_pay == minor_cost) {
outrumor(1, FALSE);
if (!u.uevent.minor_oracle)
add_xpts = u_pay / (u.uevent.major_oracle ? 25 : 10);
/* 5 pts if very 1st, or 2 pts if major already done */
u.uevent.minor_oracle = TRUE;
} else {
boolean cheapskate = u_pay < major_cost;
outoracle(cheapskate);
if (!cheapskate && !u.uevent.major_oracle)
add_xpts = u_pay / (u.uevent.minor_oracle ? 25 : 10);
/* ~100 pts if very 1st, ~40 pts if minor already done */
u.uevent.major_oracle = TRUE;
exercise(A_WIS, !cheapskate);
}
if (add_xpts) {
more_experienced(add_xpts, u_pay/50);
newexplevel();
}
return 1;
}
/*rumors.c*/